package com.cyw.common.config.aspects;

import com.cyw.common.annotations.SystemControllerLog;
import com.cyw.common.utils.JsonUtils;
import com.cyw.common.utils.LogUtils;
import com.cyw.common.utils.http.HttpUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


@Aspect
public class WebSystemLogAspect {

    private static final Logger LOGGER = LogUtils.getAccessLogger();

    private static final String EMPTY_DESC = "_";
    private ThreadLocal<Long> startTimeLocal = new ThreadLocal<>();

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     */
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        SystemControllerLog controllerLog = signature.getMethod().getAnnotation(SystemControllerLog.class);
        if (controllerLog != null) {
            return controllerLog.description();
        }
        return EMPTY_DESC;
    }

    @Pointcut("@annotation(com.ddll.base.common.annotations.SystemControllerLog)"
            + "|| @within(org.springframework.stereotype.Controller)"
            + "|| @within(org.springframework.web.bind.annotation.RestController)"
    )
    public void controllerAspect() {
    }

    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        try {
            startTimeLocal.set(System.currentTimeMillis());
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            logRequest(request, getControllerMethodDescription(joinPoint));
        } catch (Throwable e) {
            LogUtils.printWarn(e, "执行前异常");
        }
    }

    @After("controllerAspect()")
    public void doAfter(JoinPoint joinPoint) {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            long end = System.currentTimeMillis();
            long start = startTimeLocal.get();
            LOGGER.info("=====End URI:{}, cost:{}ms", request.getRequestURI(),(end - start));

        } catch (Throwable e) {
            LogUtils.printWarn(e, "执行后异常");
        }
    }

    /**
     * 打印请求日志
     */
    public static void logRequest(HttpServletRequest request, String description) {
        String ip = HttpUtils.getRequestIp(request);
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String protocol = request.getProtocol();
        LOGGER.info("=====Start URI:{}, IP:{}, Method:{}, Protocol:{}, description:{} \nParams:{} \nBody:{} \nHeaders:{}",
                uri, ip, method,
                protocol, description,
                JsonUtils.toJson(HttpUtils.getParams(request, true)),
                HttpUtils.getBodyParams(request),
                JsonUtils.toJson(HttpUtils.getHeaders(request)));
    }
}
